using System;

namespace Open.Data.Persistence.SqlServer
{
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class SqlIndexAttribute : IndexAttribute, IClusteredAttribute, ISqlIndexAttribute
    {
        //Constructors
        public SqlIndexAttribute() : base() { }
        public SqlIndexAttribute(bool unique) : base(unique) { }
        public SqlIndexAttribute(bool unique, bool clustered): base(unique)
        {
            Clustered = clustered;
        }

        //Properties
        public bool Clustered { get; set; }
        public byte FillFactor { get; set; }
        public bool IgnoreDuplicates { get; set; }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class SqlIndexColumnsAttribute : IndexColumnsAttribute, IClusteredAttribute, ISqlIndexAttribute
    {
        //Constructors
        public SqlIndexColumnsAttribute(string columns) : base(columns) { }
        public SqlIndexColumnsAttribute(string columns, bool unique) : base(columns, unique) { }
        public SqlIndexColumnsAttribute(string columns, bool unique, bool clustered): base(columns, unique)
        {
            Clustered = clustered;
        }

        //Creates a SqlIndexAttribute from any other IndexAttribute with default values
        internal SqlIndexColumnsAttribute(IIndexAttribute attribute): base("")
        {
            Unique = attribute.Unique;

            //Set defaults if not a clustered index attribute
            if (attribute is IClusteredAttribute)
            {
                IClusteredAttribute clusteredAttribute = attribute as IClusteredAttribute;
                Clustered = clusteredAttribute.Clustered;
            }
            else
            {
                Clustered = false;
            }

            //Set defaults if not a SqlIndexAttribute
            if (attribute is ISqlIndexAttribute)
            {
                ISqlIndexAttribute sqlAttribute = attribute as ISqlIndexAttribute;
                IgnoreDuplicates = sqlAttribute.IgnoreDuplicates;
                FillFactor = sqlAttribute.FillFactor;
            }
            else
            {   
                IgnoreDuplicates = false;
                FillFactor = 0;
            }

            //Get the columns if a IndexColumnsAttribute
            if (attribute is IndexColumnsAttribute)
            {
                IndexColumnsAttribute indexColumns = attribute as IndexColumnsAttribute;
                Columns = indexColumns.Columns;
            }
        }

        //Properties
        public bool Clustered { get; set; }
        public byte FillFactor { get; set; }
        public bool IgnoreDuplicates { get; set; }
    }

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class SqlIdentityAttribute : ColumnAttribute, IIdentityAttribute
    {
        //Constructors
        public SqlIdentityAttribute(int start, int increment) : base() 
        {
            Start = start;
            Increment = increment;
        }

        //Properties
        public int Start { get; set; }
        public int Increment { get; set; }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class SqlIdentityColumnAttribute : ColumnsAttribute, IIdentityAttribute 
    {
        //Constructors
        public SqlIdentityColumnAttribute(string column, int start, int increment): base(column)
        {
            //Check only one column here
            if (column.Split(",".ToCharArray()).GetLength(0) > 1) throw new ArgumentException("IdentityColumn attribute can only define one column.");
            Start = start;
            Increment = increment;
        }

        //Properties
        public int Start { get; set; }
        public int Increment { get; set; }
    }

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public class SqlPrimaryKeyAttribute : PrimaryKeyAttribute, IClusteredAttribute
    {
        //Constructors
        public SqlPrimaryKeyAttribute() : base() 
        { 
            Clustered = true;
        }
        public SqlPrimaryKeyAttribute(bool clustered) : base() 
        {
            Clustered = clustered;
        }
        public bool Clustered { get; set; }
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
    public class SqlPrimaryKeysAttribute : PrimaryKeysAttribute, IClusteredAttribute
    {
        //Constructors
        public SqlPrimaryKeysAttribute(string columns) : base(columns) 
        { 
            Clustered = true;
        }
        public SqlPrimaryKeysAttribute(string columns, bool clustered) : base(columns) 
        {
            Clustered = clustered;
        }
        internal SqlPrimaryKeysAttribute(IPrimaryKeyAttribute attribute):base("")
        {
            Clustered = false;

            if (attribute is SqlPrimaryKeyAttribute)
            {
                SqlPrimaryKeyAttribute sqlPrimaryKeyAttribute = attribute as SqlPrimaryKeyAttribute;
                Clustered = sqlPrimaryKeyAttribute.Clustered;
            }
            if (attribute is ColumnsAttribute)
            {
                ColumnsAttribute columnsAttribute = attribute as ColumnsAttribute;
                Columns = columnsAttribute.Columns;
            }
        }

        public bool Clustered { get; set; }
    }

	[AttributeUsage(AttributeTargets.Property)]
	public class SqlLengthAttribute: Attribute
	{
        //Constructors
		public SqlLengthAttribute(int length)
		{
            Length = length;
		}

        //Properties
        public int Length { get; set; }
	}

    [AttributeUsage(AttributeTargets.Property)]
    public class SqlFixedAttribute : Attribute
    {
        //Constructors
        public SqlFixedAttribute(int precision, int scale)
        {
            Precision = precision;
            Scale = scale;
        }

        //Properties
        public int Precision { get; set; }
        public int Scale { get; set; }
    }
}
